/* -----------------------------------------------------------------------------
 * PROJECT    : lwf_handlers
 * FILE       : ArithGebraProcessHandler.java
 *
 * HISTORY:
 * Date          Author                        Description
 * ----------------------------------------------------------------------------- 
 * Feb 14, 2011  mycodetalks			       Created
 */
package net.lwf.handler.math;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;
import java.util.StringTokenizer;

import lwf.handler.IProcessHandler;
import lwf.handler.ProcessHandler;
import lwf.handler.entities.RadioData;
import lwf.handler.entities.math.Sum;
import lwf.handler.helper.DisplayFormatter;
import net.lwf.common.constant.ICommonConstant;
import net.lwf.entity.QuestionInfo;
import net.lwf.handler.constant.IHandlerConstant;
import net.lwf.handler.util.SumGenerator;
import net.lwf.jaxb.entity.BaseData;
import net.lwf.jaxb.service.XMLDataService;
import net.lwf.number.util.NumberFormatter;
import net.lwf.number.util.RandomNumberGenerator;
import net.lwf.string.util.StringManipulator;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;

/**
 * Class description goes here
 */
public class ArithGebraProcessHandler extends ProcessHandler implements IProcessHandler {
	
	private String operation;
	private int digits;
	private int datarows;
	private int decimaldigits;
	private String pdfDataFile;
	private String[] pdfdata;
	private boolean needDecimals = false;
	
	//-----------------------------------------------------------------------------------
	// Constructors
	//-----------------------------------------------------------------------------------
	public ArithGebraProcessHandler(String grade, String operation, String _pdfDataFile) {
		super(grade);
		this.operation = operation;
		this.pdfDataFile = _pdfDataFile;
	}
	
	public ArithGebraProcessHandler(String grade, String operation, String _pdfDataFile, boolean needDecimals) {
		super(grade);
		this.operation = operation;
		this.pdfDataFile = _pdfDataFile;
		this.needDecimals = needDecimals;
	}

	//-----------------------------------------------------------------------------------
	// Abstract methods
	//-----------------------------------------------------------------------------------
	@Override
	public QuestionInfo generateSingle() {
		return this.generateSingle(false);
	}
	
	protected QuestionInfo generateSingle(boolean formultiple) {
		QuestionInfo qinfo = null;
		Sum sum = this.generateSum();
		//qinfo.setQuestionObject(sum.getData());
		//sum.print();
		String answer = this.getFormattedAnswer(sum.getAnswer());
		
		if(!formultiple) {
			
			if(!getOperation().equalsIgnoreCase(IHandlerConstant.DIVISION)) {
				qinfo = new QuestionInfo();
			}
			else {
				qinfo = new QuestionInfo(generateAnswerChoices(answer));
			}
			qinfo.setDecimalDigits(this.decimaldigits);
		}
		else {
			qinfo = new QuestionInfo();
		}
		qinfo.setQuestionObject(sum.getData());
		qinfo.setAnswer(answer);
		

		return qinfo;
	}
	
	protected List<RadioData> generateAnswerChoices(String baseAnswer) {
		List<RadioData> data = new ArrayList<RadioData>();
		RadioData rdata = new RadioData(baseAnswer, baseAnswer);
		data.add(rdata);
		
		StringTokenizer stk = new StringTokenizer(baseAnswer, IHandlerConstant.REMAINDER);
		String quotient = stk.nextToken().trim();
		String remainder = stk.nextToken().trim();
		int required = 3;
		List<Integer> quotients = RandomNumberGenerator.generateIntsWithVariance(Integer.parseInt(quotient), 10, required);
		List<Integer> remainders = RandomNumberGenerator.generateIntsWithVariance(Integer.parseInt(remainder), 10, required);
		for(int i=0; i< required; i++) {
			String radioinfo = String.valueOf(quotients.get(i).intValue()) + IHandlerConstant.REMAINDER + String.valueOf(remainders.get(i).intValue());
			rdata = new RadioData(radioinfo, radioinfo);
			data.add(rdata);
		}
		
		Collections.shuffle(data);
		return data;
	}
	
	@Override
	public List<QuestionInfo> generateMultiple() {
		this.initPdfInfo();
		List<QuestionInfo> questions = new ArrayList<QuestionInfo>();
		int nQuestions = getRows() * getColumns();
		for(int i=0; i<nQuestions; i++) {
			QuestionInfo question = generateSingle(true);
			question.setQuestionNumber(i+1);
			questions.add(question);
		}
		return questions;
	}

	@Override
	public int getColumns() {
		return Integer.parseInt(pdfdata[1]);
	}

	@Override
	public void getContent(Document document) throws DocumentException {
	}

	@Override
	public String getPdfInstructionalText() {
		return null;
	}

	@Override
	public int getRows() {
		return Integer.parseInt(pdfdata[0]);
	}

	@Override
	public boolean isPortrait() {
		return true;
	}
	
	@Override
	public String getPdfNote() {
		if(getOperation().equalsIgnoreCase(IHandlerConstant.DIVISION)) {
			return " Operation ' / ' = division";
		}
		return null;
	}

	//-----------------------------------------------------------------------------------
	// Interface implemented methods
	//-----------------------------------------------------------------------------------
	public DisplayFormatter getDisplayFormatter() {
		return null;
	}

	public String getQuestionDesc() {
		return null;
	}
	
	public boolean matchAnswer(String useranswer, QuestionInfo qinfo) {
		//remove "," if any
		if(useranswer != null && useranswer.trim().length() != 0) {
			useranswer = StringManipulator.replace(useranswer, ICommonConstant.COMMA, "");
		}
		//QuestionInfo qinfo = (QuestionInfo) attemptedQuestion;
		boolean returnvalue = false;
		String formattedAnswer;
		if(getOperation().equalsIgnoreCase(IHandlerConstant.DIVISION)) {
			StringTokenizer stk_ua = new StringTokenizer(useranswer.trim(), ICommonConstant.PIPE);
			if(qinfo.getDecimalDigits() == 0) {
				String ui_quotient = NumberFormatter.format(stk_ua.nextToken(), 0);
				String ui_remainder = NumberFormatter.format(stk_ua.nextToken(), 0); 
				formattedAnswer = ui_quotient + IHandlerConstant.REMAINDER + ui_remainder;
			}
			else {
				//Consider only the quotient value
				String ui_quotient = NumberFormatter.format(useranswer, qinfo.getDecimalDigits());
				formattedAnswer = ui_quotient + IHandlerConstant.REMAINDER + "0";
			}
		}
		else {
			formattedAnswer = NumberFormatter.format(useranswer.trim(), qinfo.getDecimalDigits());
		}
		
		if(qinfo.getAnswer().equalsIgnoreCase(formattedAnswer)) {
			return true;
		}

		return returnvalue;
	}
	
	//-----------------------------------------------------------------------------------
	// Other public methods
	//-----------------------------------------------------------------------------------
	public String getFormattedAnswer(Object answerobj) { //To go in a common super class
		String formattedAnswer = "";
		if(this.operation.equalsIgnoreCase(IHandlerConstant.DIVISION)) {
			String answerdata = String.valueOf(answerobj);
			String quotient = String.valueOf(answerobj);
			String remainder = "0";
			if(answerdata.indexOf(ICommonConstant.PIPE) != -1) {
				StringTokenizer stk = new StringTokenizer(answerdata, ICommonConstant.PIPE);
				quotient = stk.nextToken();
				remainder = stk.nextToken();
			}

			formattedAnswer = NumberFormatter.format(String.valueOf(quotient), this.decimaldigits) + 
			                  IHandlerConstant.REMAINDER +
			                  NumberFormatter.format(String.valueOf(remainder), this.decimaldigits);
		}
		else {
			formattedAnswer = NumberFormatter.format(String.valueOf(answerobj), this.decimaldigits);
		}
		return formattedAnswer;
	}
	
	public Sum generateSum() { //To go in a common super class
		Sum sum = null;
		if(this.operation.equalsIgnoreCase(IHandlerConstant.ADDITION)) {
			sum = SumGenerator.generateAdd(this.digits, this.datarows, this.decimaldigits);
		}
		else if(this.operation.equalsIgnoreCase(IHandlerConstant.SUBTRACTION)) {
			sum = SumGenerator.generateSubtract(this.digits, this.decimaldigits);
		}
		else if(this.operation.equalsIgnoreCase(IHandlerConstant.MULTIPLICATION)) {
			sum = SumGenerator.generateMultiply(this.digits, this.decimaldigits);
		}
		else  {
			sum = SumGenerator.generateDevide(this.digits, this.decimaldigits);
		}
		return sum;
	}
	
	public Sum getAlgebraicSumForDevide() {
		return SumGenerator.generateDevide(this.digits, 0);
	}
	
	public String getOperation() {
		return operation;
	}

	public int getDigits() {
		return digits;
	}

	public int getDatarows() {
		return datarows;
	}

	public int getDecimaldigits() {
		return decimaldigits;
	}

	public void init() {
	//private void init() {	//To go in a common super class
		XMLDataService service = new XMLDataService();
		BaseData data = service.getArithmaticData(Integer.parseInt(getGrade()), operation);
		//Read the value by JAXB code - input = grade; output = digits, decimal points
		this.digits = data.getDigits();
		this.datarows = data.getDatarows();
		if(needDecimals) {
			this.decimaldigits = data.getDecimals();
		}
	}
	
	private void initPdfInfo() {
		this.init();
		this.pdfdata = getPdfData(operation + "-" + this.digits + "-" + this.decimaldigits + "-" + this.datarows);
	}
	
	public String[] getPdfData(String key) {
		String[] pdfdata = new String[2];
		try {
			ResourceBundle bundle = ResourceBundle.getBundle(this.pdfDataFile);
			String data = bundle.getString(key);
			StringTokenizer stk = new StringTokenizer(data, ICommonConstant.PIPE);
			pdfdata[0] = stk.nextToken();
			pdfdata[1] = stk.nextToken();			
		}
		catch(Exception ex) {
			pdfdata[0] = "6";
			pdfdata[1] = "3";
		}

		return pdfdata;
	}

}



